package com.wanhe.viewconf;

import android.content.Context;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;

import com.wanhe.base.util.TypefaceUtil;
import com.wanhe.viewconf.generator.IViewGenerator;

import java.util.HashMap;
import java.util.Map;

/**
 * File Name:ViewCreator.java<br/>
 * Package Name:com.wanhe.viewconf<br/>
 * Date:2017/7/7 9:34<br/>
 * author:chendeji<br/>
 * desc: 用于生成控件的工厂类<br/>
 * Copyright (c) 2017/7/7, 781571323@qq.com All Rights Reserved.
 */
public class ViewCreator {
    private static ViewCreator ourInstance;

    private ViewOptions mViewOptions;

    /**
     * 某些文本子控件的配置项目
     *
     * @author 陈德基
     * @time 2017/7/3 15:42
     */
    private Typeface mFontTypeface;

    /**
     * 添加器控件中加减号控件是否使用字体来显示
     *
     * @author 陈德基
     * @time 2017/7/3 15:56
     */
    private boolean isPlusIconUseText;

    /**
     * 添加器中的加号按钮的图标
     *
     * @author 陈德基
     * @time 2017/7/10 9:45
     */
    private Drawable mCounterPlusDrawble;

    /**
     * 减号按钮图标
     *
     * @author 陈德基
     * @time 2017/7/10 9:46
     */
    private Drawable mCounterReduceDrawable;

    /**
     * 加减号字体文件
     *
     * @author 陈德基
     * @time 2017/7/10 9:46
     */
    private Typeface mIconTypeface;

    /**
     * 售罄图标
     *
     * @author 陈德基
     * @time 2017/7/10 9:46
     */
    private Drawable mSalloutDrawable;

    /**
     * 添加器的字体大小
     *
     * @author 陈德基
     * @time 2017/7/24 16:25
     */
    private int mCounterIconFontSize;

    /**
     * 文本的字体大小
     *
     * @author 陈德基
     * @time 2017/7/24 16:25
     */
    private int mTxtFontSize;


    /**
     * 控件扩展倍增系数
     *
     * @author 陈德基
     * @time 2017/7/10 9:47
     */
    private double mExtentionPt;

    private ViewConfig.Builder.OnInitMapData mInitListener;                            // 对外暴露的接口
    private Map<String, String> configMap;                                // 用于记录读取配置文件信息的缓存

    private Map<String, String> generatorMap = new HashMap<>();
    private Map<String, IViewGenerator> generatorNameMap = new HashMap<>();
    private Context mContext;
    private boolean isDebug;

    public boolean isDebug() {
        return isDebug;
    }

    public Typeface getFontTypeface() {
        return mFontTypeface;
    }

    public boolean isPlusIconUseText() {
        return isPlusIconUseText;
    }

    public Drawable getCounterPlusDrawble() {
        return mCounterPlusDrawble;
    }

    public Drawable getCounterReduceDrawable() {
        return mCounterReduceDrawable;
    }

    public Typeface getIconTypeface() {
        return mIconTypeface;
    }

    public Drawable getSalloutDrawable() {
        return mSalloutDrawable;
    }

    public double getExtentionPt() {
        return mExtentionPt;
    }

    public int getCounterIconFontSize() {
        return mCounterIconFontSize;
    }

    public int getTxtFontSize() {
        return mTxtFontSize;
    }

    public static ViewCreator getInstance() {
        if (ourInstance == null) {
            synchronized (ViewCreator.class) {
                if (ourInstance == null) {
                    ourInstance = new ViewCreator();
                }
            }
        }
        return ourInstance;
    }

    private ViewCreator() {
    }

    public ViewOptions getViewOptions() {
        return mViewOptions;
    }

    public void setOptions(ViewOptions viewOptions) {
        this.mViewOptions = viewOptions;
    }

    public ViewCreator setContext(Context context) {
        this.mContext = context;
        return this;
    }

    public void init(ViewConfig config) {
        this.isPlusIconUseText = config.isPlusIconUseText;
        this.mCounterPlusDrawble = config.mCounterPlusDrawble;
        this.mCounterReduceDrawable = config.mCounterReduceDrawable;
        this.mSalloutDrawable = config.mSalloutDrawable;
        this.mExtentionPt = config.mExtentionPt;
        this.configMap = config.configMap;
        this.mInitListener = config.mInitListener;
        this.isDebug = config.isDebug;
        this.mTxtFontSize = config.mTxtFontSize;
        this.mCounterIconFontSize = config.mCounterIconFontSize;

        if (mContext == null) {
            throw new NullPointerException("view creator without context");
        }
        this.mFontTypeface = TypefaceUtil.getTypeFace(mContext, config.mFontTypeface);
        this.mIconTypeface = TypefaceUtil.getTypeFace(mContext, config.mIconTypeface);

        generateViewMap();

    }

    /**
     * Methor Name:createXYView<br/>
     * Package Name:com.wanhe.viewconf<br/>
     * Date:2017/7/10 10:49<br/>
     * author:chendeji<br/>
     * desc: 根据给定的type找到指定的控件生成器<br/>
     * Copyright (c) 2017/7/10, 781571323@qq.com All Rights Reserved.
     *
     * @param type view type
     * @return {@link IViewGenerator}
     */
    public IViewGenerator createXYView(String type) {
        if ((generatorMap != null && generatorMap.size() > 0)
                && (generatorNameMap != null && generatorNameMap.size() > 0)) {
            return generatorNameMap.get(generatorMap.get(type));
        }
        return null;
    }

    private void generateViewMap() {
        if (configMap == null || configMap.size() == 0) {
            throw new NullPointerException("builder init map fail");
        }
        Map<String, String> keyValue = configMap;
        IViewGenerator generator;
        for (Map.Entry<String, String> entry : keyValue.entrySet()) {

            /**
             *
             * 将字符串转成Generator对象，存入映射表
             *
             * @author 陈德基
             * @time 2017/6/29 18:01
             */
            try {
                Class<IViewGenerator> aClass;
                generatorMap.put(entry.getKey(), entry.getValue());
                if (!generatorNameMap.containsKey(entry.getValue())) {
                    aClass = (Class<IViewGenerator>) Class
                            .forName("com.wanhe.viewconf.generator." + entry.getValue());
                    generator = aClass.newInstance();
                    generatorNameMap.put(entry.getValue(), generator);
                }
            } catch (ClassNotFoundException e) {
                /**
                 *
                 * 在这个包里没有找到相应的控件生成器，需要将流程交于外部，让外部进行另外的添加
                 *
                 * @author 陈德基
                 * @time 2017/7/3 9:59
                 */
                if (mInitListener != null) {
                    /**
                     *
                     * 防止外部的错误数据传入，或者清空。
                     *
                     * @author 陈德基
                     * @time 2017/7/3 10:17
                     */
                    Map<String, IViewGenerator> tempViewGenerator = new HashMap<>();
                    mInitListener.extentionGenerator(entry.getValue(), tempViewGenerator);
                    if (tempViewGenerator.size() > 0) {
                        for (Map.Entry<String, IViewGenerator> entrys : tempViewGenerator
                                .entrySet()) {
                            generatorNameMap.put(entrys.getKey(), entrys.getValue());
                        }
                    }
                }
            } catch (InstantiationException e) {
                if (mInitListener != null) {
                    mInitListener.onErr(e);
                }
            } catch (IllegalAccessException e) {
                if (mInitListener != null) {
                    mInitListener.onErr(e);
                }
            }
        }
    }

    public static class ViewConfig {

        /**
         * 某些文本子控件的配置项目
         *
         * @author 陈德基
         * @time 2017/7/3 15:42
         */
        private String mFontTypeface;

        /**
         * 添加器控件中加减号控件是否使用字体来显示
         *
         * @author 陈德基
         * @time 2017/7/3 15:56
         */
        private boolean isPlusIconUseText;
        private Drawable mCounterPlusDrawble;
        private Drawable mCounterReduceDrawable;
        private String mIconTypeface;
        private Drawable mSalloutDrawable;
        private double mExtentionPt;
        private boolean isDebug;

        private Builder.OnInitMapData mInitListener;            // 对外暴露的接口
        private Map<String, String> configMap;                // 用于记录读取配置文件信息的缓存

        private int mCounterIconFontSize;
        private int mTxtFontSize;

        public ViewConfig(Builder builder) {
            this.mFontTypeface = builder.mFontTypeface;
            this.isPlusIconUseText = builder.isPlusIconUseText;
            this.mCounterPlusDrawble = builder.mCounterPlusDrawble;
            this.mCounterReduceDrawable = builder.mCounterReduceDrawable;
            this.mIconTypeface = builder.mIconTypeface;
            this.mSalloutDrawable = builder.mSalloutDrawable;
            this.mExtentionPt = builder.mExtentionPt;
            this.mInitListener = builder.mInitListener;
            this.configMap = builder.configMap;
            this.mCounterIconFontSize = builder.mCounterIconFontSize;
            this.mTxtFontSize = builder.mTxtFontSize;
            this.isDebug = builder.isDebug;
        }

        /**
         * Methor Name:builder<br/>
         * Package Name:com.wanhe.viewconf<br/>
         * Date:2017/7/3 10:42<br/>
         * author:chendeji<br/>
         * desc: <br/>
         * Copyright (c) 2017/7/3, 781571323@qq.com All Rights Reserved.
         *
         * @param
         * @return {@link ViewConfig.Builder}
         */
        public static Builder builder() {
            if (builder == null) {
                synchronized (Builder.class) {
                    if (builder == null) {
                        builder = new Builder();
                    }
                }
            }
            return builder;
        }

        private static Builder builder;

        /**
         * File Name:ViewFactoryConfig.java<br/>
         * Package Name:com.wanhe.viewconf<br/>
         * Date:2017/7/3 10:45<br/>
         * author:chendeji<br/>
         * desc: 用于配置view工厂的生成器<br/>
         * 需要配置的功能有：<br/>
         * 1，控件生成器的映射关系，配置文件读取<br/>
         * 2，数量添加器中加减号的字体配置，可能是字体，也可能是icon<br/>
         * 3，配置文本控件的字体样式和字体大小
         * 4，......
         * Copyright (c) 2017/7/3, 781571323@qq.com All Rights Reserved.
         */
        public static class Builder {

            /**
             * 某些文本子控件的配置项目
             *
             * @author 陈德基
             * @time 2017/7/3 15:42
             */
            private String mFontTypeface;

            /**
             * 添加器控件中加减号控件是否使用字体来显示
             *
             * @author 陈德基
             * @time 2017/7/3 15:56
             */
            private boolean isPlusIconUseText;
            private Drawable mCounterPlusDrawble;
            private Drawable mCounterReduceDrawable;
            private String mIconTypeface;
            private Drawable mSalloutDrawable;
            private double mExtentionPt;
            private int mCounterIconFontSize;
            private int mTxtFontSize;
            private boolean isDebug;


            /**
             * File Name:ViewFactoryConfig.java<br/>
             * Package Name:com.wanhe.viewconf<br/>
             * Date:2017/7/5 17:20<br/>
             * author:chendeji<br/>
             * desc: 用于对外暴露初始化控件加载器配置的接口<br/>
             * Copyright (c) 2017/7/5, 781571323@qq.com All Rights Reserved.
             */
            public interface OnInitMapData {
                /**
                 * Methor Name:initMap<br/>
                 * Package Name:com.wanhe.viewconf<br/>
                 * Date:2017/6/29 17:53<br/>
                 * author:chendeji<br/>
                 * desc: 初始化控件加载器的映射关系<br/>
                 * Copyright (c) 2017/6/29, 781571323@qq.com All Rights
                 * Reserved.
                 *
                 * @param map 映射
                 * @return
                 */
                void initMap(Map<String, String> map);

                /**
                 * Methor Name:extentionGenerator<br/>
                 * Package Name:com.wanhe.viewconf<br/>
                 * Date:2017/7/3 10:11<br/>
                 * author:chendeji<br/>
                 * desc: <br/>
                 * Copyright (c) 2017/7/3, 781571323@qq.com All Rights Reserved.
                 *
                 * @param genName      外部扩展的控件生成器名称
                 * @param generatorMap 用于向外部暴露一定的初始化 @return
                 */
                void extentionGenerator(String genName, Map<String, IViewGenerator> generatorMap);

                void onErr(Throwable throwable);
            }

            private OnInitMapData mInitListener;    // 对外暴露的接口
            private Map<String, String> configMap;        // 用于记录读取配置文件信息的缓存

            /**
             * Methor Name:init<br/>
             * Package Name:com.wanhe.viewconf<br/>
             * Date:2017/6/29 17:48<br/>
             * author:chendeji<br/>
             * desc: 用于加载主工程映射配置文件的入口<br/>
             * Copyright (c) 2017/6/29, 781571323@qq.com All Rights Reserved.
             *
             * @param initListener {@link OnInitMapData#initMap(Map)}
             * @return {@link Builder}
             */
            public Builder init(OnInitMapData initListener) {
                this.mInitListener = initListener;
                configMap = new HashMap<>();
                if (mInitListener != null) {
                    mInitListener.initMap(configMap);
                }
                if (configMap.size() <= 0) {
                    throw new IllegalArgumentException("map no data");
                }
                return this;
            }

            /**
             * Methor Name:txtFontPath<br/>
             * Package Name:com.wanhe.viewconf<br/>
             * Date:2017/7/3 15:40<br/>
             * author:chendeji<br/>
             * desc: <br/>
             * Copyright (c) 2017/7/3, 781571323@qq.com All Rights Reserved.
             *
             * @param fontPath 在资产目录中font文件夹下的字体文件路径
             * @return {@link Builder}
             */
            public Builder txtFontPath(String fontPath) {
                this.mFontTypeface = fontPath;
                return this;
            }

            /**
             * Methor Name:txtFontSizePT<br/>
             * Package Name:com.wanhe.viewconf<br/>
             * Date:2017/7/24 16:20<br/>
             * author:chendeji<br/>
             * desc: 设置文本字体的大小<br/>
             * Copyright (c) 2017/7/24, 781571323@qq.com All Rights Reserved.
             *
             * @param size 字体大小，单位PT
             * @return {@link Builder}
             */
            public Builder txtFontSizePT(int size) {
                this.mTxtFontSize = size;
                return this;
            }

            /**
             * Methor Name:counterWithIMG<br/>
             * Package Name:com.wanhe.viewconf<br/>
             * Date:2017/7/3 15:56<br/>
             * author:chendeji<br/>
             * desc: <br/>
             * Copyright (c) 2017/7/3, 781571323@qq.com All Rights Reserved.
             *
             * @param isPlusText 是否让添加器的加减号使用文本
             * @return {@link Builder}
             */
            public Builder counterWithIMG(boolean isPlusText) {
                this.isPlusIconUseText = isPlusText;
                return this;
            }

            /**
             * Methor Name:couterImg<br/>
             * Package Name:com.wanhe.viewconf<br/>
             * Date:2017/7/3 16:05<br/>
             * author:chendeji<br/>
             * desc: 设置数量添加器中加减号的icon图标<br/>
             * Copyright (c) 2017/7/3, 781571323@qq.com All Rights Reserved.
             *
             * @param plus   加号的drawable
             * @param reduce 减号的drawble
             * @return {@link Builder}
             */
            public Builder couterImg(Drawable plus, Drawable reduce) {
                this.mCounterPlusDrawble = plus;
                this.mCounterReduceDrawable = reduce;
                return this;
            }

            /**
             * Methor Name:salloutImg<br/>
             * Package Name:com.wanhe.viewconf<br/>
             * Date:2017/7/5 10:16<br/>
             * author:chendeji<br/>
             * desc: 用于设置数量添加器的售罄图片<br/>
             * Copyright (c) 2017/7/5, 781571323@qq.com All Rights Reserved.
             *
             * @param sallout 估清icon
             * @return {@link Builder}
             */
            public Builder salloutImg(Drawable sallout) {
                this.mSalloutDrawable = sallout;
                return this;
            }

            public Builder extentionPT(double expt) {
                this.mExtentionPt = expt;
                return this;
            }

            /**
             * Methor Name:counterIconTypeface<br/>
             * Package Name:com.wanhe.viewconf<br/>
             * Date:2017/7/3 16:22<br/>
             * author:chendeji<br/>
             * desc: 如果添加器上的加减号要使用文本来显示，那么要设定文本的字体<br/>
             * Copyright (c) 2017/7/3, 781571323@qq.com All Rights Reserved.
             *
             * @param iconTypeface 加减号文本的字体文件路径
             * @return {@link Builder}
             */
            public Builder counterIconTypeface(String iconTypeface) {
                this.mIconTypeface = iconTypeface;
                return this;
            }

            /**
             * Methor Name:counterIconFontSizePt<br/>
             * Package Name:com.wanhe.viewconf<br/>
             * Date:2017/7/24 16:22<br/>
             * author:chendeji<br/>
             * desc: 添加器文本的字体大小<br/>
             * Copyright (c) 2017/7/24, 781571323@qq.com All Rights Reserved.
             *
             * @param size 文字字体大小
             * @return {@link Builder}
             */
            public Builder counterIconFontSizePt(int size) {
                this.mCounterIconFontSize = size;
                return this;
            }

            public Builder isDebug(boolean debug) {
                this.isDebug = debug;
                return this;
            }

            /**
             * Methor Name:build<br/>
             * Package Name:com.wanhe.viewconf<br/>
             * Date:2017/7/3 10:54<br/>
             * author:chendeji<br/>
             * desc: 最终将配置的数据同步到ViewFactory中<br/>
             * Copyright (c) 2017/7/3, 781571323@qq.com All Rights Reserved.
             *
             * @param
             * @return {@link ViewConfig}
             */
            public ViewConfig build() {
                return new ViewConfig(this);
            }

        }
    }

}
